package com.baixiaowen.xiaoaointerview.并发提升篇.N种优化哲学家就餐问题的方法;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 哲学家就餐问题
 *
 * @author Baixiaowen
 */
public class Philosopher implements Runnable{

    /**
     * 哲学家状态 Thinking Hungry Eating
     */
    String state;
    int id;
    /**
     * 当前这个哲学家他完成了多少次
     */
    int count = 0;
    /**
     * 完成的就餐的哲学家的数目
     */
    static AtomicInteger total = new AtomicInteger(0);
    /**
     * 开始时间
     */
    static long startMills = System.currentTimeMillis();

    public Philosopher(int id) {
        this.id = id;
        this.state = "Thinking";
    }

    /**
     * 思考
     */
    public void thinking() throws InterruptedException {
        if (this.state == "Thinking") {
            Thread.sleep((long)(Math.random() * 100));
            this.state = "Hungry";
        }
    }

    public void eating() throws InterruptedException {
        this.state = "Eating";

        // 大于0.9概率认为 Eating 过程失败，处理的较慢
        if (Math.random() > 0.9) {
            Thread.sleep(100000);
        } else { // 小于0.9概率认为 Eating 过程成功
            Thread.sleep((long)(Math.random() * 100));
        }
//        this.state = "Thinking";
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    /**
     * 左边叉子
     * @return
     */
    public int left() {
        return this.id - 1;
    }

    /**
     * 右边叉子
     * @return
     */
    public int right () {
        return this.id % 5;
    }

    private boolean _take(int[] forks, int fork) {
        if (forks[fork] == 0) {
            forks[fork] = this.id;
            return true;
        }
        return false;
    }

    /**
     * 拿左边的叉子
     * @param forks
     * @return
     */
    protected boolean takeLeft(int[] forks) {
        return this._take(forks, this.left());
    }

    /**
     * 拿右边的叉子
     * @param forks
     * @return
     */
    protected boolean takeRight(int[] forks) {
        return this._take(forks, this.right());
    }

    /**
     * 放下右边叉子
     * @param forks
     */
    protected void putRight(int[] forks) {
        if (forks[this.right()] == this.id) {
            forks[this.right()] = 0;
        }
    }

    /**
     * 放下左边叉子
     * @param forks
     */
    protected void putLeft(int[] forks) {
        if (forks[this.left()] == this.id) {
            forks[this.left()] = 0;
        }
    }

    /**
     * 检查是否可以拿左边叉子
     * @param forks
     * @return
     */
    protected boolean checkLeft(int[] forks) {
        return forks[this.left()] == 0;
    }

    /**
     * 检查是否可以拿右边叉子
     * @param forks
     * @return
     */
    protected boolean checkRight(int[] forks) {
        return forks[this.right()] == 0;
    }

    public void finished() {
        count ++;
        int t = total.incrementAndGet();
        // 一秒钟可以处理多少个哲学家就餐
        double speed = (t * 1000.0) / (System.currentTimeMillis() - startMills);
        this.state = "Thinking";
        System.err.format("Philosopher %d finished %d times, speed = %.2f.\n", this.id, this.count, speed);
    }

    @Override
    public void run() {
        throw new UnsupportedOperationException();
    }
}
